/***************************************************************
 * @file       main.cpp
 * @brief      实现project2中任意进制转换
 * @author     krasjet_Yu
 * @version    v1
 * @date       2022/3/4
 **************************************************************/

#include <iostream>
#include <vector>
#include <cstring>
#include <string.h>
#include <fstream>
using namespace std;

#define MAXN 9
#define DLEN 1

// 高精度大数类
class BigNum
{
private:
    int a[500];
    int len;
public:
    BigNum(){len=1;memset(a,0,sizeof(a));}   // 构造函数
    BigNum(const int);                       // 整数型构造函数
    BigNum(const char*);                     // 字符型构造函数
    BigNum(const BigNum&);                   // 赋值构造函数
    BigNum &operator=(const BigNum &);       // 重载赋值
    BigNum operator+(const BigNum &)const;   // 重载加法
    BigNum operator-(const BigNum &)const;   // 重载减法
    BigNum operator*(const BigNum &)const;   // 重载乘法
    BigNum operator/(const int &)const;      // 重载除法
    int operator%(const int &b)const;        // 重载取余
    bool operator>(const BigNum &T)const;    // 重载大于
    bool operator>(const int &t)const;       // 重载大于
    bool operator<(const BigNum &T)const;    // 重载小于
    bool operator<(const int &t)const;       // 重载小于
    BigNum opposite();        // 取反
    void print();
};

BigNum::BigNum(const int b)
{
    int c, d = b;
    len = 0;
    memset(a, 0, sizeof(a));
    if (b == 0)	a[len++] = d;
    while (d > MAXN)
    {
        c = d - (d / (MAXN + 1)) * (MAXN + 1);
        d = d / (MAXN + 1);
        a[len++] = c;
    }
    if (d != 0)
        a[len++] = d;
}

BigNum::BigNum(const char* s)
{
    int index, L, k, t;
    memset(a, 0, sizeof(a));
    L = strlen(s);
    len = L / DLEN;
    if (L % DLEN) len++;
    index = 0;
    for (int i = L-1; i >= 0; i-=DLEN)
    {
        t = 0;
        k = i - DLEN + 1;
        if (k < 0) k = 0;
        for (int j = k; j <= i; ++j)
        {
            t = t * 10 + (s[j] - '0');
        }
        a[index++] = t;
    }
}

BigNum::BigNum(const BigNum &T):len(T.len)
{
    int i;
    memset(a, 0, sizeof(a));
    for (i = 0; i < len; ++i)
        a[i] = T.a[i];
}

BigNum BigNum::opposite()
{
    BigNum t(*this);
    t.a[t.len-1] = -t.a[t.len-1];
    return t;
}

BigNum & BigNum::operator=(const BigNum &n)
{
    int i;
    len = n.len;
    memset(a, 0, sizeof(a));
    for (i = 0; i < len; ++i)
        a[i] = n.a[i];
    return *this;
}

BigNum BigNum::operator+(const BigNum &T)const
{
    BigNum t(*this);
    int i, big;
    big = T.len>len?T.len:len;
    for (i = 0; i < big; ++i)
    {
        t.a[i] += T.a[i];
        if (t.a[i] > MAXN)
        {
            t.a[i+1] += 1;
            t.a[i] -= MAXN + 1;
        }
    }
    if (t.a[big] != 0)
        t.len = big + 1;
    else
        t.len = big;
    return t;
}

BigNum BigNum::operator-(const BigNum &T)const
{
    if (*this < 0)
    {
        BigNum t(*this);
        // cout << "operator-: *this: ";
        // t.print();
        t = t.opposite();
        // cout << "t = 0 - t: ";
        // t.print();
        t = t + T;
        // cout << "t = t + T: ";
        // t.print();
        t = t.opposite();
        // cout << "t = m - t: ";
        // t.print();
        return t;
    }
    int i,j,big;
    bool flag;
    BigNum t1 ,t2;
    if (*this > T)
    {
        t1 = *this;
        t2 = T;
        flag = 0;
    }
    else
    {
        t1 = T;
        t2 = *this;
        flag = 1;
    }
    big = t1.len;
    for (i = 0; i < big; ++i)
    {
        if (t1.a[i] < t2.a[i])
        {
            j = i + 1;
            while (t1.a[j] == 0)
                j++;
            t1.a[j--]--;
            while (j > i)
                t1.a[j--] += MAXN;
            t1.a[i] += MAXN + 1 - t2.a[i];
        }
        else
            t1.a[i] -= t2.a[i];
    }
    t1.len = big;
    while (t1.a[t1.len-1]==0 && t1.len>1)
    {
        t1.len--;
        big--;
    }
    if (flag)
        t1.a[big-1] = 0 - t1.a[big - 1];
    return t1;
}

BigNum BigNum::operator*(const BigNum &T)const
{
    BigNum ret;
    int i, j, up;
    int temp, temp1;
    for (i = 0; i < len; ++i)
    {
        up = 0;
        for (j = 0; j < T.len; ++j)
        {
            temp = a[i] * T.a[j] + ret.a[i+j] + up;
            if (temp > MAXN)
            {
                temp1 = temp - temp / (MAXN+1) * (MAXN+1);
                up = temp / (MAXN + 1);
                ret.a[i+j] = temp1;
            }
            else
            {
                up = 0;
                ret.a[i+j] = temp;
            }
        }
        if (up != 0)
            ret.a[i+j] = up;
    }
    ret.len = i + j;
    while (ret.a[ret.len-1]==0 && ret.len>1) ret.len--;
    return ret;
}

BigNum BigNum::operator/(const int &b)const
{
    BigNum ret;
    int i, down=0;
    for (i = len-1; i >= 0; --i)
    {
        ret.a[i] = (a[i] + down * (MAXN+1)) / b;
        down = a[i] + down * (MAXN + 1) - ret.a[i] * b;
    }
    ret.len = len;
    while (ret.a[ret.len-1] == 0 && ret.len > 1)
        ret.len--;
    return ret;
}

int BigNum::operator%(const int &b)const
{
    int i, d = 0;
    for (i = len-1; i >= 0; --i)
        d = ((d*(MAXN+1))%b+a[i])%b;
    return d;
}

bool BigNum::operator>(const BigNum &T)const
{
    int ln;
    // cout << "len: " << len << "   " << "T.len: " << T.len << endl;
    if (len > T.len)
    {
        if (a[len - 1] < 0)
            return false;
        return true;
    }
    else if (len == T.len)
    {
        // cout << "len == T.len" << endl;
        ln = len - 1;
        while (a[ln] == T.a[ln] && ln >= 0)
            ln--;
        // cout << "ln: " << ln << endl;
        if (ln >= 0 && a[ln] > T.a[ln])
            return true;
        else
            return false;
    }
    else
    {
        if (T.a[T.len - 1] < 0)
            return true;
        return false;
    }
}

bool BigNum::operator>(const int &t)const
{
    BigNum b(t);
    return *this > b;
}

bool BigNum::operator<(const BigNum &T)const
{
    int ln;
    // cout << "len: " << len << "   " << "T.len: " << T.len << endl;
    if (len < T.len)
    {
        // -5 -555
        if (T.a[T.len-1] < 0)
            return false;
        return true;
    }
    else if (len == T.len)
    {
        // cout << "len == T.len" << endl;
        ln = len - 1;
        while (a[ln] == T.a[ln] && ln >= 0)
            ln--;
        // cout << "ln: " << ln << endl;
        if (ln >= 0 && a[ln] < T.a[ln])
            return true;
        else
            return false;
    }
    else
    {
        // -555 -5
        if (a[len - 1] < 0)
            return true;
        return false;
    }
}

bool BigNum::operator<(const int &t)const
{
    BigNum b(t);
    return *this < b;
}

void BigNum::print()
{
    int i;
    printf("%d", a[len-1]);
    for (i = len - 2; i >= 0; --i)
        printf("%d", a[i]);
    printf("\n");
}

/***************************************************************
 *  @brief     读取txt文件
 *  @param     path：路径, context:内容的引用
 *  @note      无
 *  @Sample usage:     函数的使用方法
 **************************************************************/
void readfile(string& path, vector<string>& context)
{
    ifstream infile;
    infile.open(path, ios::in);
    if (!infile.is_open())
    {
        cout << "open file failed!" << endl;
        return;
    }
    string s;
    while (getline(infile, s))
        context.push_back(s);
}

/***************************************************************
 *  @brief     判断是否是有效字符进制
 *  @param     char:字符进制
 *  @note      无
 *  @Sample usage:     函数的使用方法
 **************************************************************/
bool is_EfficentLetter(char ch)
{
    if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
        return true;
    return false;
}

/***************************************************************
 *  @brief     字符转int
 *  @param     字符
 *  @note      无
 *  @Sample usage:     函数的使用方法
 **************************************************************/
int char_to_int(char ch)
{
    if (ch >= '0' && ch <= '9')
        return (ch - '0');
    else if (ch >= 'a' && ch <= 'z')
        return (ch - 'a' + 10);
    else if (ch >= 'A' && ch <= 'Z')
        return (ch - 'A' + 10);
}

/***************************************************************
 *  @brief     格式是否正确
 *  @param     const char*：字符, base：进制
 *  @note      备注
 *  @Sample usage:     函数的使用方法
 **************************************************************/
bool ErrorJudge(const char* c, int base)
{
    int i, len = strlen(c);
    int t;
    for (i = 0; i < len; ++i)
    {
        if (!is_EfficentLetter(c[i]))
        {
            cout << "Please input Efficent Letter!" << endl;
            return true;
        }
        t = char_to_int(c[i]);
        if (t >= base)
        {
            cout << "Please input a number in the decimal range!" << endl;
            return true;
        }
    }
    return false;
}

bool ErrorBase(int source, int object)
{
    if ((source < 1) || (source > 26) || (object < 1) || (object > 26))
    {
        cout << "Please input correct base!" << endl;
        return true;
    }
    return false;
}

/***************************************************************
 *  @brief     char转大数BigNum
 *  @param     字符
 *  @note      无
 *  @Sample usage:     函数的使用方法
 **************************************************************/
BigNum char_to_num(char ch)
{
    if (ch >= '0' && ch <= '9')
        return BigNum(ch - '0');
    else if (ch >= 'a' && ch <= 'z')
        return BigNum(ch - 'a' + 10);
    else if (ch >= 'A' && ch <= 'Z')
        return BigNum(ch - 'A' + 10);
}

/***************************************************************
 *  @brief     int转char
 *  @param     int
 *  @note      备注
 *  @Sample usage:     函数的使用方法
 **************************************************************/
char num_to_char(int num)
{
    if (num >= 0 && num <= 9)
        return (char)('0' + num);
    else
        return (char)('a' + num - 10);
}

/***************************************************************
 *  @brief     原进制转十进制
 *  @param     const char*: 字符串, source: 原进制
 *  @note      备注
 *  @Sample usage:     函数的使用方法
 **************************************************************/
BigNum source_to_decimal(const char *temp, int source)
{
    BigNum decimal_num(0);
    BigNum Source(source);
    int length = strlen(temp);
    for (int i = 0; i <= length - 1; ++i)
        decimal_num = (decimal_num * Source) + char_to_num(temp[i]);
    return decimal_num;
}

/***************************************************************
 *  @brief     十进制转目标进制
 *  @param     char *：目标进制字符串, BigNum: 十进制, object: 目标进制
 *  @note      备注
 *  @Sample usage:     函数的使用方法
 **************************************************************/
int decimal_to_object(char* temp, BigNum decimal_num, int object)
{
    int i = 0;
    // cout << "decimal_to_object" << endl;
    // BigNum zero(0);
    // int zero = 0;
    // while(decimal_num > 0)
    while (decimal_num > 0)
    {
        temp[i] = num_to_char(decimal_num % object);
        // cout << (decimal_num % object) << endl;
        decimal_num = decimal_num / object;
        // decimal_num.print();
        // cout << (decimal_num > zero) << endl;
        // cout << decimal_num.len << endl;
        i++;
    }
    return i;
}

int main(int argc, char* argv[])
{
    string path = "/home/krasjet/ClionProjects/cplusplus_hw/BaseConversion/data.txt";
    vector<string> context;
    char sign[2];
    readfile(path, context);
//	for (auto c : context)
//	{
//		cout << c << endl;
//	}
    //int source = atoi(argv[1]);
    //int object = atoi(argv[2]);
    //cout << argv[1] << " " << argv[2] << endl;
    int source = atoi(context[2].c_str());
    int object = atoi(context[3].c_str());

    cout << "请将 " << context[0] << " 与 " << context[1] << " 相加的和从 " << source << "进制 转换到 " << object << "进制" << endl;

    for (int i = 0; i < 2; ++i)
    {
        string::iterator p = context[i].begin();
        if (context[i][0] == '-')
        {
            sign[i] = '-';
            context[i].erase(p);
        }
        else if (context[i][0] == '+')
        {
            sign[i] = '+';
            context[i].erase(p);
        }
        else
            sign[i] = '+';
    }
    const char* a = context[0].c_str();
    const char* b = context[1].c_str();
    bool a_error = ErrorJudge(a, source);
    bool b_error = ErrorJudge(b, source);
    if (a_error || b_error)
        return 1;
    bool base_error = ErrorBase(source, object);
    if (base_error)
        return 1;
    BigNum decimal[2];
    decimal[0] = source_to_decimal(a, source);
    decimal[1] = source_to_decimal(b, source);
    printf("a: \n");
    printf("%c", sign[0]);
    decimal[0].print();
    printf("b: \n");
    printf("%c", sign[1]);
    decimal[1].print();

    BigNum t;
    if (sign[0] == sign[1])
    {
        t = decimal[0] + decimal[1];
        if (sign[0] == '-')
            t = t.opposite();
    }
    else if (sign[0] == '+')
    {
        t = decimal[0] - decimal[1];
    }
    else if (sign[1] == '+')
    {
        t = decimal[1] - decimal[0];
    }

//    BigNum t(0), m(0);
//    for (int i = 0; i < 2; ++i)
//    {
//        // cout << sign[i] << endl;
//        // decimal[i].print();
//        if (sign[i] == '-')
//            t = t - decimal[i];
//        else
//            t = t + decimal[i];
//        // t.print();
//    }

    cout << "10进制相加结果为：";
    t.print();
    int flag = 0;
    if (t < 0)
    {
        // cout << "t<0" << endl;
        flag = 1;
        t = t.opposite();
    }

    char temp[600];
    int len = decimal_to_object(temp, t, object);

    cout << object <<"进制相加结果为：";
    if (flag)	cout << "-";
    for (int i = len-1; i >= 0; --i)
        cout << temp[i];
    cout << endl;
    return 0;
}